home *** CD-ROM | disk | FTP | other *** search
/ Shareware Grab Bag / Shareware Grab Bag.iso / 014 / lu.c < prev    next >
Text File  |  1985-06-03  |  16KB  |  642 lines

  1. #include <stdio.h>
  2. #include <ctype.h>
  3.  
  4. char *sbrk();
  5. char *getmem();
  6.  
  7. /*
  8.     T. Jennings 13 Jan 84
  9.  
  10.  
  11.     LU Library Utility for all MSDOS and PC DOS machines. Can be used
  12. to pack multiple files into a single LBR file for modem transfers, extract,
  13. delete or update files within an LBR file, and reorganize one.
  14.  
  15.     NOTE: Reorganizing is desireable after deleting, adding, or updating
  16. a file in the library. This due to the way LBR files are organized; deleted
  17. files dont remove the data, and new files are added to the end. The LBR will
  18. become much more compact after a Reorganization.
  19.  
  20. */
  21.  
  22. #define ACTIVE 0    /* active, non-deleted file, */
  23. #define UNUSED 0xff    /* never used slot, */
  24. #define DELETED 0xfe    /* deleted file slot, */
  25.  
  26. #define MAXNAMES 20    /* maximum number of names in command line, */
  27. #define MAXFILES 256    /* max files per LBR file, */
  28.  
  29. char names[30][MAXNAMES];/* list of names from command line, */
  30. int num_names;        /* number of names in above list, */
  31.  
  32. /* Fix some annoyances in the Lattice Library. */
  33.  
  34. long lseek();            /* not an annoyance, */
  35. #define tell(f) lseek(f,0L,1)    /* wierd */
  36. #define seek lseek        /* wrong name, */
  37.  
  38. /* This is the structure of the LBR file directory. One per slot. 
  39. THIS MUST BE COMPILED ON LATTICE WITH THE -B OPTION!!!! */
  40.  
  41. struct _ludir {
  42.     char stat;    /* file status, */
  43.     char name[11];    /* FCB type filename, */
  44.     unsigned off;    /* offset to data, (sectors) */
  45.     unsigned len;    /* length (sectors) of data, */
  46.     int fill[8];    /* fill out to 32 bytes */
  47. } ludir; /* (dummy ludir so we can sizeof() it) */
  48.  
  49. struct _ludir ldir[MAXFILES];
  50. int num_slots;        /* number of slots in LBR file, */
  51.  
  52. char lbrname[14];    /* LBR file name, */
  53. int lbr;        /* LBR file handle, */
  54. char *buf;        /* buffer from DOS, */
  55. int bufsize;        /* size of buffer, */
  56.  
  57. main(argc,argv)
  58. int argc;
  59. char *argv[];
  60. {
  61. int i;
  62. char command;
  63.  
  64.     ++argv; --argc;
  65.     if (argc < 2) {
  66.  
  67.         printf("LU -- T. Jennings 15 Jan 84\n");
  68.         printf("  LU <cmd> lbrfile file file file ...   Where <cmd> is:\n");
  69.         printf("\tT List of files in LBR file,\n");
  70.         printf("\tL Same as T,\n");
  71.         printf("\tA Extract all files from the LBR file,\n");
  72.         printf("\tE Extract file(s) from LBR file,\n");
  73.         printf("\tU Add to or create LBR file,\n");
  74.         printf("\tD Delete a file from LBR file,\n");
  75.         printf("\tR Reorganize the LBR file.\n");
  76.         exit();
  77.     }
  78.     command= *argv[0];        /* get command char, */
  79.     strcpy(lbrname,argv[1]);    /* blindly get LBR name, */
  80.     for (i= 0; i < argc - 2; i++) {
  81.         strcpy(names[i],argv[i + 2]);
  82.         stoupper(names[i]);
  83.     }
  84.     num_names= i;
  85.  
  86.     allmem();            /* find largest area to allocate */
  87.     bufsize= sizmem() - (MAXFILES * sizeof(ludir)) - 2000;
  88.     if (bufsize < 512) {
  89.         printf("Not enough memory\n");
  90.         exit();
  91.     }
  92.     buf = getmem(bufsize);
  93.  
  94.     switch (tolower(command)) {
  95.         case 'a':
  96.             unpack();
  97.             break;
  98.         case 't':
  99.         case 'l':
  100.             list();
  101.             break;
  102.         case 'e':
  103.             extract();
  104.             break;
  105.         case 'u':
  106.             update();
  107.             break;
  108.         case 'd':
  109.             delete();
  110.             break;
  111.         case 'r':
  112.             reorg();
  113.             break;
  114.         default:
  115.             printf("Not a command.\n");
  116.             break;
  117.     }
  118. }
  119. /* Update: add or change a file. If the library file does not exist, then
  120. create it and ask for the number of slots. Delete any file of the same
  121. name first, then add it in. */
  122.  
  123. update() {
  124.  
  125. int i;
  126.  
  127.     if (get_directory() == -1) {        /* open or create, */
  128.         if (new_directory() == -1) {
  129.             printf("Error: cant create new directory\n");
  130.             return;            /* error! */
  131.         }
  132.     }
  133.     for (i= 0; i < num_names; i++) {    /* add each file, */
  134.         if (find(names[i]) != -1) printf("Updating existing file %s\n",names[i]);
  135.         else printf("Adding new file %s\n",names[i]);
  136.         kill(names[i]);            /* delete first, */
  137.         if (add_file(names[i]) == 0)    /* add in, if error, */
  138.             break;
  139.     }
  140.     put_directory();            /* close LBR file, */
  141. }
  142. /* Delete all the specified names from the directory. */
  143.  
  144. delete() {
  145.  
  146. int i;
  147.     if (get_directory() == -1) {
  148.         printf("Error: LBR file not found\n");
  149.         return;
  150.     }
  151.     for (i= 0; i < num_names; i++) {
  152.         if (find(names[i]) != -1) 
  153.             printf("Deleting %s\n",names[i]);
  154.         else printf("%s not in library\n",names[i]);
  155.         kill(names[i]);
  156.     }
  157.     put_directory();
  158. }
  159.  
  160. /* List all the files in the LBR file. */
  161.  
  162. list() {
  163.  
  164. int i;
  165. long size;
  166. char name[14];
  167. int active,deleted,empty;
  168.  
  169.     size= 0L; active= deleted= empty= 0;
  170.  
  171.     if (get_directory() == -1) {
  172.         printf("Error: LBR file not found\n");
  173.         return;
  174.     }
  175.     for (i= 0; i < num_slots; i++) {
  176.         if (ldir[i].stat == ACTIVE) {
  177.             cvt_from_fcb(ldir[i].name,name);
  178.             printf("%-16s %8lu %8u\n",name,
  179.               (long)ldir[i].len * 128L,ldir[i].off);
  180.             size+= (long)ldir[i].len * 128L;
  181.             ++active;
  182.         }
  183.         if (ldir[i].stat == DELETED) ++deleted;
  184.         if (ldir[i].stat == UNUSED) ++empty;
  185.     }
  186.     printf("%-16s %8lu total bytes\n","",size);
  187.     printf("%u active files, %u deleted files, %u empty slots.\n",
  188.         active,deleted,empty);
  189. }
  190.  
  191. /* Unpack all files from the library. */
  192.  
  193. unpack() {
  194.  
  195. int i;
  196. int slot;
  197. long pos,size;
  198. unsigned count;
  199. int file;
  200. char name[14];
  201.  
  202.     if (get_directory() == -1) {
  203.         printf("Error: LBR file not found\n");
  204.         return;
  205.     }
  206.     for (slot= 1; slot < num_slots; slot++) {
  207.         if (ldir[slot].stat == ACTIVE) {
  208.             cvt_from_fcb(ldir[slot].name,name);
  209.             printf("Extracting %s\n",name);
  210.             file= creat(name,0x8001);    /* make new file, */
  211.             if (file == -1) {        /* check error, */
  212.                 printf("Error: cant create %s\n",name);
  213.                 break;
  214.             }
  215.             pos= (long)ldir[slot].off * 128L;    /* find offset, */
  216.             size= (long)ldir[slot].len * 128L;    /* and file size, */
  217.             seek(lbr,pos,0);        /* go there, */
  218.             while (size > 0L) {        /* copy out data, */
  219.                 count= (size > bufsize ? bufsize : size);
  220.                 read(lbr,buf,count);    /* read data, */
  221.                 write(file,buf,count);    /* write it, */
  222.                 size-= count;        /* update count, */
  223.             }
  224.             close(file);
  225.         }
  226.     }
  227.     close(lbr);
  228. }
  229. /* Extract all specified files. */
  230.  
  231. extract() {
  232.  
  233. int i;
  234. int slot;
  235. long pos,size;
  236. unsigned count;
  237. int file;
  238.  
  239.     if (get_directory() == -1) {
  240.         printf("Error: LBR file not found\n");
  241.         return;
  242.     }
  243.     for (i= 0; i < num_names; i++) {
  244.         slot= find(names[i]);
  245.         if (slot != -1) {
  246.             printf("Extracting %s\n",names[i]);
  247.             file= creat(names[i],0x8001);    /* make new file, */
  248.             if (file == -1) {        /* check error, */
  249.                 printf("Error: cant create %s\n",names[i]);
  250.                 break;
  251.             }
  252.             pos= (long)ldir[slot].off * 128L;    /* find offset, */
  253.             size= (long)ldir[slot].len * 128L;    /* and file size, */
  254.             seek(lbr,pos,0);        /* go there, */
  255.             while (size > 0L) {        /* copy out data, */
  256.                 count= (size > bufsize ? bufsize : size);
  257.                 read(lbr,buf,count);    /* read data, */
  258.                 write(file,buf,count);    /* write it, */
  259.                 size-= count;        /* update count, */
  260.             }
  261.             close(file);
  262.         } else printf("%s not in library\n",names[i]);
  263.     }
  264.     close(lbr);
  265. }
  266.  
  267. /* Find the specified file in the directory, return its slot number 
  268. or -1 if not found. */
  269.  
  270. find(name)
  271. char *name;
  272. {
  273. int i;
  274. char fname[14];
  275.  
  276.     for (i= 0; i < num_slots; i++) {        /* search all slots, */
  277.         cvt_from_fcb(ldir[i].name,fname);    /* convert for compare */
  278.         if (strcmp(name,fname) == 0)        /* if found, */
  279.             return(i);            /* return slot number, */
  280.     }
  281.     return(-1);                    /* not found, */
  282. }
  283. /* Delete the specified file. No error return. */
  284.  
  285. kill(name)
  286. char *name;
  287. {
  288. int slot;
  289.  
  290.     slot= find(name);                /* find it, */
  291.     if (slot != -1) ldir[slot].stat= DELETED;    /* delete it, */
  292. }
  293.  
  294. /* Find a free slot in the directory. Return -1 if none. */
  295.  
  296. free_slot() {
  297.  
  298. int i;
  299.  
  300.     for (i= 0; i < num_slots; i++) {
  301.         if (ldir[i].stat == UNUSED) return(i);
  302.         if (ldir[i].stat == DELETED) return(i);
  303.     }
  304.     return(-1);
  305. }
  306. /* Add a file to the library. All files get added to the end. Returns 0 
  307. if couldnt add; either file not found or no room. No check is made that the
  308. file might exist already, etc. */
  309.  
  310. add_file(name)
  311. char *name;
  312. {
  313.  
  314. int i,file,slot;
  315. unsigned count;
  316. long size,pos;
  317.  
  318.     slot= free_slot();            /* find a free slot, */
  319.     if (slot == -1) {            /* if none, return 0 */
  320.         printf("No room in directory\n");
  321.         return(0);
  322.     }
  323.     file= open(name,0x8000);        /* get file, */
  324.     if (file == -1) {
  325.         printf("Cant find %s\n",name);
  326.         return(0);
  327.     }
  328.  
  329.     seek(lbr,0L,2);                /* seek to end of file, */
  330.     pos= tell(lbr);                /* save position, */
  331.     size= 0L;                /* init file size, */
  332.     while (count= read(file,buf,bufsize)) {    /* copy data, */
  333.         size+= count;            /* get file size, */
  334.         write(lbr,buf,count);        /* write to library, */
  335.     }
  336.  
  337.     for (i= 0; i < 128; i++)
  338.         buf[i]= 0x1a;            /* clear dummy data, */
  339.     count= 128 - (size % 128L);        /* make LBR file a */
  340.     if (count > 0) write(lbr,buf,count);    /* multiple of 128, */
  341.     cvt_to_fcb(name,ldir[slot].name);    /* install name, */
  342.     ldir[slot].off= pos / 128L;        /* position, (sectors) */
  343.     ldir[slot].len= (size + 127L) / 128L;    /* size, (sectors) */
  344.     ldir[slot].stat= ACTIVE;
  345.  
  346.     close(file);
  347.     return(1);
  348. }
  349. /* Reorganize an LBR file. This consists of creating a new LBR, and copying
  350. all entries to it. This removes any space comsumed by deleted files, etc. */
  351.  
  352. reorg() {
  353.  
  354. struct _ludir odir[MAXFILES];
  355. int old,i,n,count;
  356. long size,pos;
  357. char oldname[14],tempname[14],buff[512];
  358. int old_slots,slot;
  359. char *p,*s;
  360.  
  361.     if (get_directory() == -1) {
  362.         printf("Error: cant find library\n");
  363.         return;
  364.     }
  365.     p= (char *)&ldir[0];        /* copy old directory, */
  366.     s= (char *)&odir[0];
  367.     for (i= (num_slots * sizeof(ludir)); i; i--)
  368.         *s++= *p++;
  369.     old= lbr;            /* old LBR handle, */
  370.     old_slots= num_slots;
  371.     strcpy(oldname,lbrname);    /* old LBR name, */
  372.     printf("Old library has %u slots\n",old_slots);
  373.     strcpy(lbrname,"lu$$$$$$.tmp");    /* make temp file, */
  374.     new_directory();        /* create new one, */
  375.  
  376.     slot= 0;
  377.     for (i= 1; i < old_slots; i++) {
  378.         if (odir[i].stat == ACTIVE) {
  379.             if (++slot >= num_slots) {
  380.                 printf("Not enough room in new directory\n");
  381.                 break;
  382.             }
  383.             cvt_from_fcb(odir[i].name,tempname);
  384.             printf("Copying %s\n",tempname);
  385.             seek(old,(long)odir[i].off * 128L,0);    /* seek to old data, */
  386.             seek(lbr,0L,2);                /* EOF on new file, */
  387.             pos= tell(lbr);                /* current position, */
  388.             size= odir[i].len * 128L;
  389.             while (size > 0L) {
  390.                 count= (size > sizeof(buff) ? sizeof(buff) : size);
  391.                 read(old,buff,count);
  392.                 write(lbr,buff,count);
  393.                 size-= count;
  394.             }
  395.             ldir[slot].stat= ACTIVE;        /* update new */
  396.             ldir[slot].len= odir[i].len;        /* directory, */
  397.             cvt_to_fcb(tempname,ldir[slot].name);
  398.             ldir[slot].off= (pos + 127L) / 128L;
  399.         }
  400.     }
  401.     put_directory();        /* close new directory, */
  402.     close(old);            /* close old, */
  403.     unlink(oldname);        /* delete old one, */
  404.     link("lu$$$$$$$.tmp",oldname);    /* back to original name */
  405. }
  406. /* Read the directory. */
  407.  
  408. get_directory()
  409. {
  410. unsigned size;
  411. int i;
  412.  
  413.     lbr= open(lbrname,0x8002);
  414.     if (lbr == -1) return(-1);
  415.  
  416.     if (read(lbr,&ldir[0],sizeof(ludir)) != sizeof(ludir))
  417.         return(-1);
  418.  
  419.     num_slots= (ldir[0].len * 128) / sizeof(ludir);
  420.     size= (num_slots - 1) * sizeof(ludir);    /* already read one, */
  421.     if (num_slots > MAXFILES) {
  422.         printf("Directory error: %s is bad or not an LBR file\n",lbrname);
  423.         return(-1);
  424.     }
  425.     if (read(lbr,&ldir[1],size) != size) {
  426.         printf("Directory error: is %s an LBR file?\n",lbrname);
  427.         return(-1);
  428.     }
  429.     return(1);
  430. }
  431.  
  432. /* Create a new directory. When we request the number of slots, always round it
  433. up to the nearest 128 bytes, i.e. 4 slots. Since everything is a multiple
  434. of 128 anyways, all were doing is making otherwose wasted space available. */
  435.  
  436. new_directory() {
  437.  
  438. int i;
  439.  
  440.     num_slots= 0;
  441.     do {    cprintf("Number of slots (4 - 256, 0 to abort): ");
  442.         getstring(buf);
  443.         cprintf("\r\n");
  444.         num_slots= atoi(buf);
  445.     } while (num_slots > 256);
  446.     if (num_slots == 0) return(-1);
  447.     num_slots+= num_slots % (128 / sizeof(ludir));
  448.  
  449.     lbr= creat(lbrname,0x8002);
  450.     if (lbr == -1) return(-1);
  451.     cvt_to_fcb(".",ldir[0].name);
  452.     ldir[0].len= (num_slots * sizeof(ludir)) / 128;
  453.     ldir[0].stat= ACTIVE;
  454.     for (i= 1; i < MAXFILES; i++) {    /* clear ALL slots, */
  455.         cvt_to_fcb(".",ldir[i].name);
  456.         ldir[i].len= 0;
  457.         ldir[i].off= 0;
  458.         ldir[i].stat= UNUSED;
  459.     }
  460.     put_directory();        /* write to disk, */
  461.     return(get_directory());    /* read in new directory, */
  462. }
  463.  
  464. /* Write the directory out.  */
  465.  
  466. put_directory() {
  467.  
  468. int count;
  469.  
  470.     count= ldir[0].len * 128;
  471.     seek(lbr,0L,0);            /* to start of file, */
  472.     if (write(lbr,&ldir[0],count) != count)
  473.         printf("LBR close error: library may be trashed\n");
  474.     close(lbr);
  475. }
  476.  
  477.  
  478. /* Convert a normal asciz string to MSDOS/CPM FCB format. Make the filename
  479. portion 8 characters, extention 3 maximum. */
  480.  
  481. cvt_to_fcb(inname,outname)
  482. char *inname;
  483. char outname[];
  484. {
  485. char c;
  486. int i;
  487.  
  488.     if (inname[1] == ':')             /* if a drive spec, */
  489.         inname= &inname[2];        /* lop it off, */
  490.  
  491.     for (i= 0; i < 11; i++)
  492.         outname[i]= ' ';        /* clear out name, */
  493.     outname[i]= '\0';            /* null terminate, */
  494.     for (i= 0; i < 11; i++) {
  495.         if (*inname == '\0')        /* if null, */
  496.             outname[i]= ' ';    /* pad with blanks, */
  497.         else if (*inname == '.') {    /* if a dot, */
  498.             ++inname;        /* skip it, */
  499.             i= 7;            /* skip to extention, */
  500.         } else {
  501.             outname[i]= toupper(*inname);
  502.             ++inname;
  503.         }
  504.     }
  505.     return;
  506. }
  507. /* Convert a CP/M like filename to a normal ASCIZ name. Filter out characters
  508. undersireable on MSDOS. */
  509.  
  510. cvt_from_fcb(inname,outname)
  511. char *inname,*outname;
  512. {
  513. int i;
  514. char c;
  515.  
  516.     for (i= 8; i != 0; i--) {        /* do name portion, */
  517.         c= toupper(*inname);
  518.         ++inname;
  519.         if (c != ' ')             /* if not space, */
  520.             *outname++= c;        /* set it, */
  521.     }                    /* do all 8 chars, */
  522.  
  523.     if (*inname != ' ') {            /* if there is an extention, */
  524.         *outname++= '.';        /* add the dot, */
  525.         for (i= 3; i != 0; i--) {    /* do extention, */
  526.             c= toupper(*inname);
  527.             ++inname;
  528.             if (c == ' ')
  529.                 break;
  530.             *outname++= c;
  531.         }
  532.     }
  533.     *outname= '\0';                /* terminate it, */
  534.     return;
  535. }
  536. /* Get an input string; return NULL if error or empty line. Provide the
  537. usual minimum editing capabilities.  */
  538.  
  539. getstring(string)
  540. char string[];
  541. {
  542. int count;
  543. char c;
  544. char *p;
  545. int pi;
  546.     count= 0;
  547.  
  548.     while (1) {
  549.  
  550.         c= getch();            /* get a character, */
  551.         switch (c) {
  552.         case 0x0d:            /* process it, */
  553.         case 0x0a:
  554.         case 0x1b:
  555.             string[count]= 0x00;    /* terminate string, */
  556.             return(count);        /* return string length */
  557.             break;
  558.  
  559.         case 0x08:
  560.         case 0x7f:            /* delete character */
  561.         case 0x13:
  562.             if (count) {
  563.                 --count;    /* one less char, */
  564.                 putch('\010');
  565.                 putch(' ');
  566.                 putch('\010');
  567.             }
  568.             break;
  569.             case 0x18:
  570.         case 0x15:            /* delete line */
  571.         case 0x19:
  572.         case 0x03:
  573.             while (count) {
  574.                 --count;
  575.                 putch('\010');
  576.                 putch(' ');
  577.                 putch('\010');
  578.             }
  579.             break;
  580.         case 0x04:            /* retype character, */
  581.             if (string[count])
  582.                 putch(string[count++]);
  583.             break;
  584.         case 0x12:            /* retype line, */
  585.             while (string[count]) {
  586.                 putch(string[count++]);
  587.             }
  588.             break;
  589.  
  590.         default:            /* insert character */
  591.             if ( (c > 0x1f) && (c < 0x7f) && (count < 80) ) {
  592.                 string[count++] =toupper(c);
  593.                 string[count]= 0x00;
  594.                 putch(c);
  595.             } else
  596.                 putch(0x07);
  597.             break;
  598.         }
  599.     }
  600. }
  601. /* ATOI() function missing from Lattice C. From Kernighan and Richie. */
  602.  
  603. atoi(s)
  604. char s[];
  605. {
  606. int i,n;
  607.  
  608.     n= 0;
  609.     for (i= 0; s[i] >= '0' && s[i] <= '9'; ++i) 
  610.         n= 10*n + s[i]-'0';
  611.     return(n);
  612. }
  613. /* Convert a string to all upper case. */
  614.  
  615. stoupper(s)
  616. char *s;
  617. {
  618.     while (*s) {
  619.         *s= toupper(*s);
  620.         ++s;
  621.     }
  622. }
  623. /* Missing Lattice C function: File rename
  624.  
  625.     error= link(oldname,newname); */
  626.  
  627. link(old,new)
  628. char *old,*new;
  629. {
  630. char fcb[36];
  631. int i;
  632. char *p;
  633.  
  634.     for (i= 0; i < sizeof(fcb); i++)    /* clear it out first, */
  635.         fcb[i]= '\0';
  636.  
  637.     cvt_to_fcb(old,&fcb[1]);        /* first name, */
  638.     cvt_to_fcb(new,&fcb[17]);        /* new name, */
  639.     return(bdos(23,&fcb) == 0xff);        /* do it. */
  640. }
  641.  
  642.